<template>
  <div class="br-layout-relative" v-loading="transLoading" :element-loading-text="tranLoadingText">
    <div class="br-layout-relative">
      <div class="br-layout-absolute br-border-bottom" style="top:0;height: 30px;line-height: 30px;">
        <div class="br-horizontal-layout menu-bar">
          <div class="text" title="保存" @click="saveTrans">
            <svg-icon icon-class="save"></svg-icon>
          </div>
          <div class="text" title="回撤">
            <svg-icon icon-class="back-enabled"></svg-icon>
          </div>
          <div class="text" title="重做">
            <svg-icon icon-class="forward-enabled"></svg-icon>
          </div>
        </div>
      </div>
      <div class="br-layout-absolute" style="top:31px;">
        <div id="graph" class="br-layout-relative"></div>
      </div>
    </div>


    <component :is="stepDialogForm" :dialogName="stepDialogName" :ref="stepDialogForm" v-if="stepDialog" :dialog="stepDialog"
      :attributes="stepAttributes" :getDatabaseNames="getDatabaseNames" :getPreviousSteps="getPreviousSteps"
      :getExportModelXML="getExportModelXML" :getAfterSteps="getAfterSteps" @getAttributes="getStepAttributes"
      @close-dialog="closeStepDialog"></component>

  </div>
</template>

<script>
  import mxgraph from '@/graph/index'
  import {
    genGraph,
    destroyGraph,
    Graph
  } from '@/graph/Graph'
  import {
    addStep,
    saveTrans,
    getTransformation,
  } from '@/api/trans/trans'
  import {
    mapGetters
  } from 'vuex'
  const {
    mxGraph,
    mxOutline,
    mxEvent,
    mxCell,
    mxGeometry,
    mxUtils,
    mxCodec,
    mxEventObject,
    mxConstants,
    mxPerimeter,
    mxConnectionHandler,
    mxClipboard,
    mxUndoManager,
    mxKeyHandler
  } = mxgraph
  export default {
    components: {
    },
    data() {
      return {
        graph: null,

        stepName: "",
        stepDialogName: '',
        stepDialog: false,
        stepDialogForm: "",
        stepDialogLoading: false,
        stepAttributes: {},

        transLoading: false,
        tranLoadingText: "",

        transName: "",
        directoryId: "",

        databases: [],
        slaveServers: [],
        clusterSchemas: [],
        partitionSchemas: [],
        isCueCell: false,
      }
    },
    computed: {
      ...mapGetters(['sidebar']),
      isHeight() {
        return this.sidebar.height
      }
    },
    methods: {
      getTransformation() {
        this.transLoading = true;
        this.tranLoadingText = "流程正在初始化，请稍等";
        getTransformation({
          transName: this.transName,
          directoryId: this.directoryId
        }).then((res) => {
          this.transLoading = false;
          this.tranLoadingText = "";
          if (res.data.status === 200) {
            const encode = res.data.data;
            this.initGraph(encode);
            this.initCopies();
            this.initDatabaseList();
            this.initSlaveServersList();
            this.initClusterSchemasList();
            this.initPartitionSchemasList();
            this.makeDraggable();
            this.listenerGraphEvent();
            this.createPopupMenu();
          }
        })
      },
      initGraph(encode) {
        this.graph = genGraph(document.getElementById('graph'));
        let xmlDocument = mxUtils.parseXml(encode);
        let decoder = new mxCodec(xmlDocument);
        let node = xmlDocument.documentElement;
        decoder.decode(node, this.graph.getModel());
      },
      //初始化复制数
      initCopies() {
        let cells = this.graph.getDefaultParent().children;
        if (cells && cells.length) {
          Object.values(cells).forEach((cell, index) => {
            if (cell.isVertex()) {
              if (cell.value.tagName === "Step") {
                this.addCopies(cell);
              }
            }
          });
        }
      },
      addCopies(cell) {
        let copies = cell.getAttribute("copies");
        let copiesDoc = mxUtils.createXmlDocument();
        let copiesElement = copiesDoc.createElement('Copies');
        copiesElement.setAttribute("label", "X" + copies);
        this.graph.getModel().beginUpdate();
        try {
          this.graph.insertVertex(cell, null, copiesElement, -0.2, -0.4, 13, 13,
            'constituent=1;whiteSpace=wrap;strokeColor=none;fillColor=none;fontColor=#303133;', true);
        } finally {
          this.graph.getModel().endUpdate();
        }
        let children = cell.children;
        Object.values(children).forEach((child, index) => {
          child.setConnectable(false);
          if (child.value.tagName === "Copies") {
            if (copies == 1) {
              child.setVisible(false);
            } else {
              child.setVisible(true);
            }
          }
        });
        this.graph.refresh();
      },

      initDatabaseList() {
        let cell = this.graph.getDefaultParent();
        if (cell) {
          let arr = [];
          let databases = cell.getAttribute("databases");
          this.databases = JSON.parse(databases);
        }
      },
      initSlaveServersList() {
        let cell = this.graph.getDefaultParent();
        if (cell) {
          let arr = [];
          let slaveServers = cell.getAttribute("slaveServers");
          this.slaveServers = JSON.parse(slaveServers);
        }
      },
      initClusterSchemasList() {
        let cell = this.graph.getDefaultParent();
        if (cell) {
          let arr = [];
          let clusterSchemas = cell.getAttribute("clusterSchemas");
          this.clusterSchemas = JSON.parse(clusterSchemas);
        }
      },
      initPartitionSchemasList() {
        let cell = this.graph.getDefaultParent();
        if (cell) {
          let arr = [];
          let partitionSchemas = cell.getAttribute("partitionSchemas");
          this.partitionSchemas = JSON.parse(partitionSchemas);
        }
      },
      //插入
      makeDraggable() {
        let me = this;
        const dropValidate = function(evt) {
          const x = mxEvent.getClientX(evt);
          const y = mxEvent.getClientY(evt);
          const elt = document.elementFromPoint(x, y);
          if (mxUtils.isAncestorNode(me.graph.container, elt)) {
            return me.graph
          }
          return null
        };
        const dropSuccess = function(_graph, evt, target, x, y) {
          let img = this.element.getElementsByTagName("img")[0];
          let src = img.getAttribute('src');
          let params = {
            graphXml: me.graph.exportModelXML(),
            pluginId: img.getAttribute('data-pluginId'),
            name: img.getAttribute('alt')
          };
          addStep(params).then((res) => {
            if (res.data.status === 200) {
              let cell = me.graph.importModelXML(res.data.data, x, y, src);
              me.addCopies(cell);
            }
          })
        };
        let sources = document.getElementsByClassName('dragg-source');
        Array.from(sources).forEach((source) => {
          let img = source.getElementsByTagName("img")[0];
          let dragElt = document.createElement('div');
          let dragImg = document.createElement('img');
          dragElt.setAttribute('style',
            'width:40px;height:40px;border: 1px solid #d2d2e4;text-align: center;');
          dragImg.setAttribute('src', img.getAttribute('src'));
          dragImg.setAttribute('style', 'width:40px;height:40px;vertical-align: middle;');
          dragElt.appendChild(dragImg);
          mxUtils.makeDraggable(source, dropValidate, dropSuccess, dragElt,
            null, null, null, true)
        })
      },
      //监听事件
      listenerGraphEvent() {
        let me = this;
        this.graph.addListener(mxEvent.DOUBLE_CLICK, (sender, evt) => {
          let cell = evt.getProperty('cell');
          me.editStep(cell);
        });
        this.graph.addListener(mxEvent.CELL_CONNECTED, (sender, evt) => {});
        this.graph.addListener(mxEvent.CLICK, (sender, evt) => {
          let cell = evt.getProperty('cell');
          if (cell && cell.isVertex() && cell.value.tagName === "Step") {
            this.stepName = cell.getAttribute("label");
          }
        });
      },

      editStep(cell) {
        if (cell.value.tagName === "Step") {
          let pluginId = cell.getAttribute('pluginId');
          this.stepDialogForm = pluginId;
          this.stepDialogName = cell.getAttribute('label');
        }
        this.stepAttributes = cell.value.attributes;
        this.stepDialog = true;
      },
      closeStepDialog(value) {
        this.stepDialog = false;
      },
      closeFieldDialog(value) {
        this.fieldDialog = false;
      },
      isExistCellByLabel(label) {
        let isExist = false;
        let cells = this.graph.getDefaultParent().children;
        if (cells && cells.length !== 0) {
          Object.values(cells).forEach((cell, index) => {
            if (cell.isVertex()) {
              if (cell.value.tagName === "Step") {
                if (label === cell.getAttribute("label")) {
                  isExist = true;
                }
              }
            }
          });
        }
        return isExist;
      },
      copyCell(cell) {
        let i = 2;
        let label = cell.getAttribute("label") + i;
        while (this.isExistCellByLabel(label)) {
          i++;
          label = label + i;
        }
        mxClipboard.copy(this.graph, copyCell);
        let copyCell = mxClipboard.paste(this.graph);
        copyCell[0].setAttribute("label", label);
        this.graph.refresh();
      },
      changeCopies(cell) {
        this.$prompt('改变开始复制的数量', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputPattern: /^[1-9]\d*$/,
          inputErrorMessage: '不小于1的整数',
          inputValue: cell.getAttribute("copies")
        }).then(({
          value
        }) => {
          cell.setAttribute("copies", value);
          let children = cell.children;
          Object.values(children).forEach((child, index) => {
            if (child.value.tagName === "Copies") {
              child.setAttribute("label", "X" + value);
              if (value === 1) {
                child.setVisible(false);
              } else {
                child.setVisible(true);
              }
            }
          });
          this.graph.refresh(cell);
        }).catch(() => {});
      },
      //输入字段
      inputFields(cell) {
        let parmas = {
          graphXml: this.graph.exportModelXML(),
          stepName: cell.getAttribute("label"),
          before: true
        };
        this.getFieldInfo(parmas);
      },
      //输出字段
      outputFields(cell) {
        let parmas = {
          graphXml: this.graph.exportModelXML(),
          stepName: cell.getAttribute("label"),
          before: false
        };
        this.getFieldInfo(parmas);
      },
      getFieldInfo(parmas) {
        this.fieldDialog = true;
        this.fieldDialogForm = "FieldDialog";
        this.fieldDialogLoading = true;
        this.fieldTableData.splice(0);
        getFieldInfo(parmas).then((res) => {
          this.fieldDialogLoading = false;
          if (res.data.status === 200) {
            this.fieldTableData = res.data.data;
            if (parmas.before) {
              this.fieldDialogName = "输入字段";
            } else {
              this.fieldDialogName = "输出字段";
            }
          }
        })
      },

      //检查步骤
      checkStep(cell) {
        this.check(true);
      },

      //右击菜单
      createPopupMenu() {
        let me = this;
        this.graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {
          if (cell) {
            if (cell.isVertex()) {
              if (cell.value.tagName === "Step") {
                menu.addItem('编辑步骤', null, function() {
                  me.editStep(cell);
                });
                let dataPull = menu.addItem('数据发送模式', null, null);
                let distribute = cell.getAttribute("distribute");
                let text = ' 负载均衡模式',
                  text1 = ' 全量复制模式';
                if (distribute === "Y") {
                  text = '√ 负载均衡模式';
                } else {
                  text1 = '√ 全量复制模式';
                }
                menu.addItem(text, null, function() {
                  cell.setAttribute("distribute", "Y");
                  me.graph.refresh();
                }, dataPull);
                menu.addItem(text1, null, function() {
                  cell.setAttribute("distribute", "N");
                  me.graph.refresh();
                }, dataPull);

                menu.addItem('改变开始复制的数量', null, function() {
                  me.changeCopies(cell);
                });
                menu.addItem('复制步骤', null, function() {
                  me.copyCell(cell);
                });
                menu.addItem('删除步骤', null, function() {
                  me.graph.removeCells();
                });
              }
            } else if (cell.isEdge()) {
              menu.addItem('删除节点连接', null, function() {
                me.graph.removeCells();
              });
            }
          } else {
            menu.addItem('全选', null, function() {
              me.graph.selectAll();
            });
            menu.addItem('清除选择', null, function() {
              me.graph.clearSelection();
            });
          }
        };
      },

      //赋值
      setAttribute(attributes, cell) {
        Object.keys(attributes).forEach((key) => {
          let value = attributes[key];
          if (typeof value === "string" || !isNaN(Number(value))) {
            cell.setAttribute(key, value);
          } else {
            cell.setAttribute(key, JSON.stringify(value));
          }
        });
        this.graph.refresh(cell);
      },

      getStepAttributes(attributes) {
        let cell = this.graph.getSelectionCells()[0];;
        this.setAttribute(attributes, cell);
        this.stepDialog = false;
      },

      saveTrans() {
        this.transLoading = true;
        this.tranLoadingText = "流程正在保存中，请稍等";
        let parmas = {
          graphXml: this.graph.exportModelXML()
        };
        saveTrans(parmas).then((res) => {
          this.transLoading = false;
          this.tranLoadingText = "";
          if (res.data.status === 200) {
            this.$router.back(-1)
          }
        })
      },

      getDatabaseNames() {
        let cell = this.graph.getDefaultParent();
        let databases = JSON.parse(cell.getAttribute("databases"));
        let names = [];
        databases.forEach((item, index) => {
          names.push(item.displayName);
        });
        return names;
      },

      getPreviousSteps() {
        let sources = [];
        let cell = this.graph.getSelectionCells()[0];
        if (cell && cell.isVertex() && cell.value.tagName === "Step") {
          let edges = cell.edges;
          if (edges && edges.length) {
            Object.values(edges).forEach((edge, index) => {
              let source = edge.source;
              if (source && source.getAttribute("label") !== cell.getAttribute("label")) {
                sources.push(source.getAttribute("label"));
              }
            });
          }
        }
        return sources;
      },

      getAfterSteps() {
        let targets = [];
        let cell = this.graph.getSelectionCells()[0];
        if (cell && cell.isVertex() && cell.value.tagName === "Step") {
          let edges = cell.edges;
          if (edges && edges.length) {
            Object.values(edges).forEach((edge, index) => {
              let target = edge.target;
              if (target && target.getAttribute("label") !== cell.getAttribute("label")) {
                targets.push(target.getAttribute("label"));
              }
            });
          }
        }
        return targets;
      },
      getExportModelXML() {
        return this.graph.exportModelXML();
      },
    },

    created() {},
    mounted() {
      let this_=this;
      this.transName = this.$route.query.tranId;
      this.directoryId = this.$route.query.directoryId
      setTimeout(() => {
        this_.getTransformation();
      }, 500)
    },
    beforeDestroy() {
      if (this.graph)
        destroyGraph();
    }
  }
</script>

<style lang="less" scoped>
  .menu-bar {
    align-items: center;
  }

  .menu-bar .text {
    display: inline-block;
    width: 25px;
    height: 25px;
    line-height: 25px;
    margin: 0 5px;
    text-align: center;
    cursor: pointer;
  }

  .menu-bar .text i {
    color: #606266;
    font-size: 20px;
    vertical-align: middle;
    cursor: pointer;
  }

  .menu-bar .text i:hover {
    color: #3685f2;
    cursor: pointer;
  }

  #graph {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: #FFFFFF url('../../../../../assets/images/grid.gif') 0 0 repeat;
  }
</style>
